/*
 * @(#)AbstractTemplateResult.java $version 2010. 8. 11
 *
 * Copyright 2007-2010 NHN Corp. All rights Reserved. 
 * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.nhncorp.usf.core.result.template;

import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.nhncorp.lucy.web.helper.ServletHelper;
import com.nhncorp.lucy.web.util.FreeMarkerUtil;
import com.nhncorp.usf.core.Constants;
import com.nhncorp.usf.core.UsfDispatcher;
import com.nhncorp.usf.core.config.AttributeInfo;
import com.nhncorp.usf.core.config.AttributeInfo.ATTRIBUTE_NAME;
import com.nhncorp.usf.core.config.runtime.ResultPageInfo;
import com.nhncorp.usf.core.result.AbstractResult;
import com.nhncorp.usf.core.result.template.directive.TemplateDirectiveType;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * Template 타입의 {@link Result} 추상 클래스.
 *
 * @author Web Platform Development Team.
 */
@SuppressWarnings("serial")
public abstract class AbstractTemplateResult extends AbstractResult {
    /**
     * template 언어.
     */
    protected String language = "freemarker";
    
    public static final String PROPERTY_PAGE_BUFFER_SIZE = "pageBufferSize";
    
    private Map<String, Template> secondTemplateCache = new ConcurrentHashMap<String, Template>();
    
    /**
     * template 언어 설정.
     *
     * @param language String
     */
    public void setLanguage(String language) {
        this.language = language;
    }              
    
    /**
     * Execute.
     *
     * @param resultPage ResultPageInfo
     * @param dataMap Map<String, Object>
     * @param src String
     * @param configuration Configuration
     * @param response HttpServletResponse
     * @throws Exception the exception
     */
    public void execute(ResultPageInfo resultPage,  Map<String, Object> dataMap, String src, Configuration configuration, HttpServletResponse response) throws Exception {
    	Template template;
    	
        if (src.endsWith(FreeMarkerUtil.FREEMARKER_EXT)) {
            template = FreeMarkerUtil.getTemplate(configuration, src, null, null);
        } else {
            template = secondTemplateCache.get(resultPage.getId());

            if (template == null) {
                template = FreeMarkerUtil.createTemplate(configuration, resultPage.getId(), src);

                // if devMode is true, template is not cached.
                if (!UsfDispatcher.getInstance().isDevMode()) {
                    secondTemplateCache.put(resultPage.getId(), template);
                }
            }
        }

        if (template == null) {
            throw new NotExistTemplateException("can't create template (" + src + ")");
        }

        HttpServletRequest request = ServletHelper.getRequest();
        dataMap.put(Constants.FREEMARKER_KEY_REQUEST, request);
        dataMap.put(Constants.FREEMARKER_KEY_RESPONSE, response);

        setTemplateDirective(configuration, dataMap);

        try {
            template.process(dataMap, response.getWriter());
        } catch (Exception e) {
            throw new TemplateProcessException(e);
        }
    }
    
    /**
     * Sets the template directive.
     *
     * @param configuration the configuration
     * @param dataMap       the data map
     */
    @SuppressWarnings("unchecked")
	private void setTemplateDirective(Configuration configuration, Map dataMap) {
        for (TemplateDirectiveType type : TemplateDirectiveType.values()) {
            configuration.setSharedVariable(TemplateDirectiveType.getType(type),
                                            TemplateDirectiveType.getUSFTemplateDirective(type, dataMap));
        }
    }

    /**
     * Proerty(pageBufferSize)값을 {@link HttpServletResponse}에 bufferSize로 설정.
     *
     * @param resultPage 결과 페이지 설정
     * @param response   bufferSize를 설정할 {@HttpServletResponse}객체
     */
    protected void setPageBufferSize(ResultPageInfo resultPage, HttpServletResponse response) {
        Object bufferProperty;
        Properties properties = resultPage.getProperties();
        AttributeInfo attributeInfo = AttributeInfo.getInstance();
        bufferProperty = (properties == null) ? attributeInfo.getAttribute(ATTRIBUTE_NAME.pageBufferSize)
                : properties.get(PROPERTY_PAGE_BUFFER_SIZE);

        if (bufferProperty == null || ((String)bufferProperty).length() == 0) {
            bufferProperty = attributeInfo.getAttribute(ATTRIBUTE_NAME.pageBufferSize);
        }

        log.debug("buffer size : " + (String)bufferProperty);

        if (bufferProperty != null) {
            response.setBufferSize(Integer.valueOf((String)bufferProperty));
        }
    }
}
